<?php declare(strict_types=1);

/**
 * @package SimpleChat (Light Portal)
 * @link https://custom.simplemachines.org/index.php?mod=4244
 * @author Bugo <bugo@dragomano.ru>
 * @copyright 2023-2025 Bugo
 * @license https://opensource.org/licenses/MIT MIT
 *
 * @category plugin
 * @version 06.11.25
 */

namespace LightPortal\Plugins\SimpleChat;

use Bugo\Compat\Theme;
use Bugo\Compat\Utils;
use LightPortal\Enums\Tab;
use LightPortal\Plugins\Block;
use LightPortal\Plugins\Event;
use LightPortal\Plugins\PluginAttribute;
use LightPortal\UI\Fields\CheckboxField;
use LightPortal\UI\Fields\NumberField;
use LightPortal\UI\Fields\RadioField;
use LightPortal\Utils\Traits\HasView;

use Ramsey\Collection\Map\NamedParameterMap;

use const LP_ACTION;
use const LP_BASE_URL;

if (! defined('LP_NAME'))
	die('No direct access...');

/**
 * Generated by PluginMaker
 */
#[PluginAttribute(icon: 'fas fa-message')]
class SimpleChat extends Block
{
	use HasView;

	private array $defaultParams = [
		'show_avatars'     => false,
		'form_position'    => 'bottom',
		'window_height'    => 100,
		'refresh_interval' => 2,
	];

	private readonly Chat $chat;

	public function __construct()
	{
		parent::__construct();

		$this->chat = new Chat($this->name, $this->sql);
	}

	public function addSettings(): void
	{
		$table = new Table($this->sql);
		$table->createTable();
	}

	public function prepareBlockParams(Event $e): void
	{
		$e->args->params = $this->defaultParams;
	}

	public function validateBlockParams(Event $e): void
	{
		$e->args->params = [
			'show_avatars'     => FILTER_VALIDATE_BOOLEAN,
			'form_position'    => FILTER_DEFAULT,
			'window_height'    => FILTER_VALIDATE_INT,
			'refresh_interval' => FILTER_VALIDATE_INT,
		];
	}

	public function prepareBlockFields(Event $e): void
	{
		$options = $e->args->options;

		CheckboxField::make('show_avatars', $this->txt['show_avatars'])
			->setTab(Tab::APPEARANCE)
			->setValue($options['show_avatars']);

		RadioField::make('form_position', $this->txt['form_position'])
			->setOptions(array_combine(['bottom', 'top'], $this->txt['form_position_set']))
			->setValue($options['form_position']);

		NumberField::make('window_height', $this->txt['window_height'])
			->setAttribute('step', 10)
			->setAttribute('min', 0)
			->setValue($options['window_height']);

		NumberField::make('refresh_interval', $this->txt['refresh_interval'])
			->setAttribute('min', 0)
			->setValue($options['refresh_interval']);
	}

	public function prepareContent(Event $e): void
	{
		$this->loadDependencies();

		[$id, $parameters] = [$e->args->id, $e->args->parameters];

		$parameters = $this->mergeWithDefaultParams($parameters);

		$this->chat->setInSidebar($this->isInSidebar($id));
		$this->chat->setParameters($parameters);

		$messages = $this->getCachedMessages($id, $e->args->cacheTime);

		Utils::$context['lp_chats'][$id] = json_encode($messages, JSON_UNESCAPED_UNICODE);

		$this->handleChatRequests($id, $e->args->cacheTime);

		echo $this->view(params: [
			'id'          => $id,
			'baseUrl'     => LP_BASE_URL,
			'parameters'  => $parameters,
			'isInSidebar' => $this->isInSidebar($id)
		]);
	}

	public function onBlockRemoving(Event $e): void
	{
		$delete = $this->sql->delete('lp_simple_chat_messages')
			->where(['block_id' => $e->args->items]);

		$this->sql->execute($delete);
	}

	private function loadDependencies(): void
	{
		Theme::loadCSSFile('admin.css');
		Theme::loadJavaScriptFile(
			'https://cdn.jsdelivr.net/npm/htmx.org@2/dist/htmx.min.js',
			[
				'defer'    => true,
				'external' => true,
			]
		);
	}

	private function mergeWithDefaultParams(NamedParameterMap $parameters): NamedParameterMap
	{
		foreach ($this->defaultParams as $key => $value) {
			if (! $parameters->containsKey($key)) {
				$parameters->put($key, $value);
			}
		}

		return $parameters;
	}

	private function getCachedMessages(int $id, int $cacheTime): array
	{
		return $this->cache($this->name . '_addon_b' . $id)
			->setLifeTime($cacheTime)
			->setFallback(fn() => $this->chat->getMessages($id));
	}

	private function handleChatRequests(int $id, int $cacheTime): void
	{
		if ($this->request()->isNot(LP_ACTION) || $this->request()->has('preview')) {
			return;
		}

		if ($this->request()->has('chat')) {
			$action = $this->request()->get('chat');

			if ($action === 'add_message') {
				$this->chat->addMessage();
			} elseif ($action === 'remove_message') {
				$this->chat->deleteMessage();
			} else {
				$blockId = (int) $this->request()->get('id') ?: $id;
				$messagesToRender = $this->getCachedMessages($blockId, $cacheTime);
				$this->chat->renderMessages($messagesToRender, $blockId);
			}
		}
	}
}
